package com.handle.system.svc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.handle.common.core.constants.Constant;
import com.handle.common.core.dto.token.User;
import com.handle.common.core.result.JsonResult;
import com.handle.common.core.utils.ContextHolderUtils;
import com.handle.common.core.utils.CusAccessObjectUtil;
import com.handle.common.core.utils.PageUtil;
import com.handle.common.datascope.annotation.DataScope;
import com.handle.common.log.publish.PublishFactory;
import com.handle.common.redis.generator.RedisIdGenerator;
import com.handle.system.api.constants.ResponseEnum;
import com.handle.system.api.dto.SysUserDto;
import com.handle.system.api.entity.SysUser;
import com.handle.system.api.entity.SysUserRole;
import com.handle.system.api.feign.RemoteOauth2Service;
import com.handle.system.api.request.user.ResetPasswordParam;
import com.handle.system.api.request.user.UserAddParam;
import com.handle.system.api.request.user.UserQueryParam;
import com.handle.system.api.request.user.UserUpdateParam;
import com.handle.system.api.response.UserInfoVo;
import com.handle.system.api.response.UserListVo;
import com.handle.system.api.service.ISysUserService;
import com.handle.system.svc.mapper.SysRoleMapper;
import com.handle.system.svc.mapper.SysUserMapper;
import com.handle.system.svc.mapper.SysUserRoleMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统用户表 服务实现类
 * </p>
 *
 * @author zhangqing
 * @since 2021-03-05
 */
@AllArgsConstructor
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    private final SysUserMapper sysUserMapper;
    private final RemoteOauth2Service oauth2Service;
    private final SysRoleMapper sysRoleMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final RedisIdGenerator redisIdGenerator;

    @Override
    public SysUserDto loadByLoginNameAndTenantCode(String loginName, String tenantCode) {
        return sysUserMapper.loadByLoginNameAndTenantCode(loginName, tenantCode);
    }

    @Override
    public JsonResult login(String loginName, String password, String tenantCode) {
        log.info("系统服务->登录->参数: 登录名:{},密码:{},租户:{}", loginName, password, tenantCode);
        SysUserDto sysUserDto = sysUserMapper.loadByLoginNameAndTenantCode(loginName, tenantCode);
        if(StringUtils.isEmpty(sysUserDto)){
            PublishFactory.recordLoginLog(loginName,Constant.LOGIN_FAIL,ResponseEnum.USER_NOT_EXISTS.getMessage(),tenantCode);
            ResponseEnum.USER_NOT_EXISTS.assertFail();
        }
        if(sysUserDto.getRoles().isEmpty()){
            PublishFactory.recordLoginLog(loginName,Constant.LOGIN_FAIL,ResponseEnum.ROLE_IS_NULL.getMessage(),tenantCode);
            ResponseEnum.ROLE_IS_NULL.assertFail();
        }
        ResponseEnum.USER_PASSWORD_NOT_MATCH.assertIsFalse(new BCryptPasswordEncoder().matches(password,sysUserDto.getPassword()));
        if (!sysUserDto.getStatus()) {
            PublishFactory.recordLoginLog(loginName, Constant.LOGIN_FAIL, ResponseEnum.USER_BLOCK.getMessage(), tenantCode);
            ResponseEnum.USER_BLOCK.assertFail();
        }
        if (sysUserDto.getDelFlag()) {
            PublishFactory.recordLoginLog(loginName, Constant.LOGIN_FAIL, ResponseEnum.USER_DELETE.getMessage(), tenantCode);
            ResponseEnum.USER_DELETE.assertFail();
        }
        if (sysUserDto.getTenant().getDelFlag()) {
            PublishFactory.recordLoginLog(loginName, Constant.LOGIN_FAIL, ResponseEnum.TENANT_DELETE.getMessage(), tenantCode);
            ResponseEnum.TENANT_DELETE.assertFail();
        }
        if (!sysUserDto.getTenant().getStatus()) {
            ResponseEnum.TENANT_BLOCK.assertFail();
        }

        Map<String, String> map = new HashMap<>(16);
        map.put("client_id", Constant.SYSTEM_CLIENT_ID);
        map.put("client_secret","123456");
        map.put("grant_type", "password");
        map.put("tenant_code", tenantCode);
        map.put("username", loginName);
        map.put("password", password);
        JsonResult accessToken = oauth2Service.getAccessToken(map);

        // 记录最后登录ip,和时间
        sysUserDto.setLoginIp(CusAccessObjectUtil.getIpAddress(ContextHolderUtils.getRequest()));
        sysUserDto.setLoginDate(LocalDateTime.now());
        sysUserMapper.updateUser(sysUserDto);

        PublishFactory.recordLoginLog(loginName, Constant.LOGIN_SUCCESS, "登录成功", tenantCode);
        return accessToken;
    }

    @Override
    public UserInfoVo info(Long userId,String tenantId) {
        UserInfoVo info = sysUserMapper.info(userId);
        ResponseEnum.USER_NOT_EXISTS.assertIsEmpty(info);
        return info;
    }

    @Override
    @DataScope(deptTableAlias = "sd", userTableAlias = "su")
    public JsonResult list(UserQueryParam userParam) {
        PageUtil.startPageSort(userParam.getPageNum(), userParam.getPageSize(),userParam.getSortField(),userParam.getSortOrder());
        List<UserListVo> list = sysUserMapper.list(userParam);
        return JsonResult.success(PageUtil.restPage(list));
    }

    /**
     * 批量删除用户信息
     *
     * @param ids 需要删除的数据ID
     * @return 影响的结果行
     */
    @Override
    public int delUserByIds(List<Long> ids){
        log.info("系统服务->批量删除用户->参数: ids:{}",ids.toString());
        List<SysUser> sysUsers = sysUserMapper.selectBatchIds(ids);
        boolean contains = sysUsers.stream().map(SysUser::getId).collect(Collectors.toList()).contains(1L);
        if (contains) {
            ResponseEnum.ADMIN_NOT_DEL.assertFail();
        }
        return sysUserMapper.delUserByIds(ids);
    }

    @Override
    public int changeStatus(Long id, Boolean status) {
        log.info("系统服务->修改用户状态->参数: id:{},状态:{}",id,status);
        SysUser sysUser = sysUserMapper.selectById(id);
        ResponseEnum.USER_NOT_EXISTS.assertIsEmpty(sysUser);
        sysUser.setStatus(status);
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    public int resetPassword(ResetPasswordParam resetPasswordParam) {
        log.info("系统服务->重置用户密码->参数: {}", resetPasswordParam.toString());
        SysUser sysUser = sysUserMapper.selectById(resetPasswordParam.getId());
        ResponseEnum.USER_NOT_EXISTS.assertIsEmpty(sysUser);
        String encodePassword = new BCryptPasswordEncoder().encode(resetPasswordParam.getPassword());
        sysUser.setPassword(encodePassword);
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(UserUpdateParam userUpdateParam) {
        log.info("系统服务->修改用户->参数: {}", userUpdateParam.toString());
        SysUser sysUser1 = sysUserMapper.selectById(userUpdateParam.getId());
        ResponseEnum.USER_NOT_EXISTS.assertIsEmpty(sysUser1);
        if (!userUpdateParam.getRoleIds().isEmpty()) {
            // 删除该用户所关联的角色,重新插入新进来的
            UpdateWrapper<SysUserRole> like = new UpdateWrapper<SysUserRole>()
                    .eq(SysUserRole.USER_ID, userUpdateParam.getId());
            sysUserRoleMapper.delete(like);
            List<SysUserRole> sysUserRoles = new ArrayList<>();
            // 重新封装
            userUpdateParam.getRoleIds().forEach(roleId -> {
                SysUserRole sysUserRole = new SysUserRole()
                        .setUserId(userUpdateParam.getId())
                        .setRoleId(roleId);
                sysUserRoles.add(sysUserRole);
            });
            sysUserRoleMapper.batchAddUserRole(sysUserRoles);
        }
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userUpdateParam,sysUser);
        return sysUserMapper.updateUser(sysUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int add(UserAddParam userAddParam) {
        log.info("系统服务->添加用户->参数: {}", userAddParam.toString());
        long userId = redisIdGenerator.nextId(Constant.SYS_USER_KEY);
        List<SysUserRole> sysUserRoles = new ArrayList<>();

        if (!StringUtils.isEmpty(userAddParam.getRoleIds())) {
            // 封装
            userAddParam.getRoleIds().forEach(roleId -> {
                SysUserRole sysUserRole = new SysUserRole()
                        .setUserId(userId)
                        .setRoleId(roleId);
                sysUserRoles.add(sysUserRole);
            });
            sysUserRoleMapper.batchAddUserRole(sysUserRoles);
        }
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userAddParam,sysUser);
        sysUser.setId(userId);
        sysUser.setPassword(new BCryptPasswordEncoder().encode("123456"));
        User currentUser = ContextHolderUtils.getCurrentUser();
        sysUser.setTenantCode(userAddParam.getTenantCode());
        sysUser.setCreateStaff(currentUser.getUserId());
        sysUser.setCreateTime(LocalDateTime.now());
        return sysUserMapper.insert(sysUser);
    }

    @Override
    public Boolean checkPhoneUnique(String phone, Long userId) {
        log.info("系统服务->校验手机号码是否唯一->参数: 用户id: {} 手机号码: {}", userId, phone);
        LambdaQueryWrapper<SysUser> like = new QueryWrapper<SysUser>().lambda()
                .eq(SysUser::getPhone, phone)
                .notIn(!StringUtils.isEmpty(userId),SysUser::getId, userId);
        SysUser sysUser = sysUserMapper.selectOne(like);
        if (!StringUtils.isEmpty(sysUser)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Boolean checkEmailUnique(String email, Long userId) {
        log.info("系统服务->校验邮箱是否唯一->参数: 用户id: {} 邮箱: {}", userId, email);
        QueryWrapper<SysUser> like = new QueryWrapper<SysUser>()
                .eq(SysUser.EMAIL, email)
                .notIn(!StringUtils.isEmpty(userId),SysUser.ID, userId);
        SysUser sysUser = sysUserMapper.selectOne(like);
        if (!StringUtils.isEmpty(sysUser)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public Boolean checkLoginNameUnique(String loginName) {
        log.info("系统服务->校验登录名是否唯一->参数: 登录名: {}", loginName);
        LambdaQueryWrapper<SysUser> like = new QueryWrapper<SysUser>().lambda()
                .eq(SysUser::getLoginName, loginName);
        SysUser sysUser = sysUserMapper.selectOne(like);
        if (!StringUtils.isEmpty(sysUser)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }
}
